package dao

import (
	"gitee.com/huangxinbo/xcas/internal/app/base"
	"gitee.com/huangxinbo/xcas/internal/model/db_model"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type UserDAO struct {
	base *base.Base
}

func NewUserDAO(base *base.Base) *UserDAO {
	return &UserDAO{
		base: base,
	}
}

func (d *UserDAO) Create(ctx *gin.Context, user *db_model.User) error {
	if err := d.base.Db.WithContext(ctx).Create(user).Error; err != nil {
		d.base.Logger.Error("Failed to create user", zap.Error(err))
		return err
	}
	return nil
}

func (d *UserDAO) GetByID(ctx *gin.Context, id string) (*db_model.User, error) {
	var user db_model.User
	if err := d.base.Db.WithContext(ctx).First(&user, "id = ?", id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		d.base.Logger.Error("Failed to get user by ID", zap.String("id", id), zap.Error(err))
		return nil, err
	}
	return &user, nil
}

func (d *UserDAO) GetByEmail(ctx *gin.Context, email string) (*db_model.User, error) {
	var user db_model.User
	if err := d.base.Db.WithContext(ctx).Where("email = ?", email).First(&user).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		d.base.Logger.Error("Failed to get user by email", zap.String("email", email), zap.Error(err))
		return nil, err
	}
	return &user, nil
}

func (d *UserDAO) GetByMobile(ctx *gin.Context, mobile string) (*db_model.User, error) {
	var user db_model.User
	if err := d.base.Db.WithContext(ctx).Where("mobile = ?", mobile).First(&user).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		d.base.Logger.Error("Failed to get user by mobile", zap.String("mobile", mobile), zap.Error(err))
		return nil, err
	}
	return &user, nil
}

func (d *UserDAO) List(ctx *gin.Context, offset, limit int) ([]*db_model.User, int64, error) {
	var users []*db_model.User
	var total int64

	if err := d.base.Db.WithContext(ctx).Model(&db_model.User{}).Count(&total).Error; err != nil {
		d.base.Logger.Error("Failed to count users", zap.Error(err))
		return nil, 0, err
	}

	if err := d.base.Db.WithContext(ctx).Offset(offset).Limit(limit).Find(&users).Error; err != nil {
		d.base.Logger.Error("Failed to list users", zap.Error(err))
		return nil, 0, err
	}

	return users, total, nil
}

// Update 更新用户信息
func (d *UserDAO) Update(ctx *gin.Context, user *db_model.User) error {
	if err := d.base.Db.WithContext(ctx).Save(user).Error; err != nil {
		d.base.Logger.Error("Failed to update user", zap.String("id", user.ID), zap.Error(err))
		return err
	}
	return nil
}

// Delete 物理删除用户
func (d *UserDAO) Delete(ctx *gin.Context, userID string) error {
	if err := d.base.Db.WithContext(ctx).Unscoped().Where("id = ?", userID).Delete(&db_model.User{}).Error; err != nil {
		d.base.Logger.Error("Failed to delete user", zap.String("id", userID), zap.Error(err))
		return err
	}
	return nil
}
